perm filename EFTP.BPL[11,HE] blob
sn#656302 filedate 1982-04-29 generic text, type T, neo UTF8
// EFTP.BPL
// Copyright Xerox Corporation 1979
GET "EFTP.HDR"
//----------------------------------------------------------------
LET INITEFTPPACKAGE(PACKAGEZONE) BE [ LET A=0 ]
//----------------------------------------------------------------
//----------------------------------------------------------------
AND OPENEFTPSOC(SOC,LCLPORT,FRNPORT) BE
//----------------------------------------------------------------
[
ZERO(SOC,LENEFTPSOC)
SOC!TRANSFERNOTSTARTED:= TRUE
SOC!CURRENTTIMEOUT:= STARTINGTIMEOUT
OPENLEVEL1SOCKET(SOC,LCLPORT,FRNPORT)
]
//----------------------------------------------------------------
AND CLOSEEFTPSOC(SOC) BE
//----------------------------------------------------------------
[
IF SOC!ABORTPBI NE 0 THEN
RELEASEPBI(SOC!ABORTPBI)
CLOSELEVEL1SOCKET(SOC)
]
//----------------------------------------------------------------
AND SENDEFTPBLOCK(SOC,ADDR,BYTECNT,TIMEOUT) = VALOF
//----------------------------------------------------------------
[
LET RESULT = SENDEFTPPACKET(SOC,ADDR,BYTECNT,TIMEOUT,TYPEEFTPDATA)
IF RESULT GE 0 THEN SOC!SEQNUM:= SOC!SEQNUM+1
RESULTIS RESULT
]
//----------------------------------------------------------------
AND SENDEFTPEND(SOC,TIMEOUT) = VALOF
//----------------------------------------------------------------
//THE END SEQUENCE REQUIRES A COMPLETE ACK FOR THE FIRST
//OUTGOING END, AND THEN AN EXTRA END IS SENT, AS PART OF THE
//THREE WAY HANDSHAKE.
[
IF SENDEFTPPACKET(SOC,0,0,TIMEOUT,TYPEEFTPEND) GE 0 THEN
[ //FIRST END SENT AND ACKED OK
LET PBI = NIL
SOC!SEQNUM:= SOC!SEQNUM+1
//SECOND END NEEDS NO TIMEOUT OR ACK
PBI:= GETPBI(SOC,FALSE)
PBI!ID2:= SOC!SEQNUM
COMPLETEPUP(PBI,TYPEEFTPEND,PUPOVBYTES)
RESULTIS TRUE
]
RESULTIS FALSE
]
//----------------------------------------------------------------
AND SENDEFTPPACKET(SOC,ADDR,DATABYTES,TIMEOUT,TYP) = VALOF
//----------------------------------------------------------------
// THIS IS A GENERAL ROUTINE, USABLE FOR DATA OR END PACKETS
// WILL HANDLE RETRANSMISSIONS HERE. PASSES IN A LONG TIMEOUT
// RETURNS THE NUMBER OF DATA BYTES SENT (>=0) IF OK;
// RETURNS AN ERROR CODE (< 0) IF THERE WAS AN ERROR
[
LET LONGTIMER = NIL;
SETTIMER(LV SOC!STARTTIME,0) //REMEMBER START TIME
SETTIMER(LV LONGTIMER,TIMEOUT)
[
// CONSTRUCT THE OUTGOING PACKET
LET SHORTTIMER = NIL
LET PBI = GETPBI(SOC,FALSE)
PBI!ID2:= SOC!SEQNUM
IF DATABYTES GR 0 THEN
MOVEBLOCK(LV PBI!(WORDS+0),ADDR,(DATABYTES+1)/2)
COMPLETEPUP(PBI,TYP,DATABYTES+PUPOVBYTES)
SETTIMER(LV SHORTTIMER,SOC!CURRENTTIMEOUT)
[
BLOCK() REPEATUNTIL SOC!IQHEAD NE 0 |
(TIMEOUT NE -1 & TIMERHASEXPIRED(LV LONGTIMER)) |
TIMERHASEXPIRED(LV SHORTTIMER)
IF TIMEOUT NE -1 & TIMERHASEXPIRED(LV LONGTIMER) THEN
RESULTIS EFTPTIMEOUT //HE IS NOT ANSWERING NOW
IF TIMERHASEXPIRED(LV SHORTTIMER) THEN
[
//EXPONENTIALLY AGE RETRANSMISSION INTERVAL
AGETIMEOUT(SOC)
BREAK //RE-TRANSMIT
]
PBI:= DEQUEUE(LV SOC!IQ); IF PBI EQ 0 BREAK
//CHECK THE SOURCE OF THIS PACKET
UNLESS MULTEQ(LV SOC!FRNSOCKET,LV PBI!SSOCKET,2) DO
[ RELEASEPBI(PBI); LOOP ]
//GOT A PACKET REALLY FOR US FROM OUR PARTNER
AGETIMEOUT(SOC)
SWITCHON (PBI!TYPE & #377) INTO
[
CASE TYPEEFTPACK:
[
IF PBI!ID2 EQ SOC!SEQNUM THEN
[ RELEASEPBI(PBI); RESULTIS DATABYTES ]
IF PBI!ID2 GR SOC!SEQNUM THEN
[
SENDEFTPABORT(SOC,OUTOFSYNCHABORT,
"YOUR RECEIVER HAS GOTTEN OUT OF SYNCH.",PBI)
RELEASEPBI(PBI)
RESULTIS EFTPABORTSENT
]
RELEASEPBI(PBI)
ENDCASE
]
CASE TYPEEFTPABORT:
[
IF SOC!ABORTPBI NE 0 THEN
RELEASEPBI(SOC!ABORTPBI)
SOC!ABORTPBI:= PBI
RESULTIS EFTPABORTRECEIVED // BAIL OUT
]
DEFAULT: RELEASEPBI(PBI)
]
] REPEAT
] REPEAT
]
//----------------------------------------------------------------
AND AGETIMEOUT(SOC) BE
//----------------------------------------------------------------
//UPDATE THE ADAPTIVE TIMEOUT
// = 2 TIMES THE AVERAGE RESPONSE TIME, EXPONENTIALLY AGED OVER
// THE LAST 8 SAMPLES.
[
LET T = NIL; SETTIMER(LV T,0)
T:= ((T-SOC!STARTTIME) LSHIFT 3) +4
SOC!CURRENTTIMEOUT:= (7*SOC!CURRENTTIMEOUT+
MAX(MINTIMEOUT,MIN(MAXTIMEOUT,T))) RSHIFT 3
]
//----------------------------------------------------------------
AND RECEIVEEFTPBLOCK(SOC,ADDR,TIMEOUT) = VALOF
//----------------------------------------------------------------
// RETURNS A BYTE COUNT (>=0) OR AN ERROR CODE (<0)
[
LET INPBI = 0
LET RECEIVERESULT = RECEIVEEFTPPACKET(SOC, TIMEOUT, LV INPBI)
IF RECEIVERESULT GR 0 THEN // SUCCEEDED
[
MOVEBLOCK(ADDR, LV INPBI!(WORDS+0),
(RECEIVERESULT+1) RSHIFT 1)
IF INPBI THEN [ RELEASEPBI(INPBI); IF RECEIVERESULT EQ 0 LOOP ] // IGNORE ZERO-LENGTH PACKETS
RESULTIS RECEIVERESULT // COUNT OF DATABYTES
]
UNLESS RECEIVERESULT EQ EFTPNOTFIRSTSYNCH RESULTIS RECEIVERESULT
] REPEAT
//------------------------------------------------------------------
AND RECEIVEEFTPPACKET(SOC, TIMEOUT, LVPBI) = VALOF
//------------------------------------------------------------------
// RETURNS A BYTE COUNT (>=0) OR AN ERROR CODE (<0)
// IF A BYTE COUNT, @LVPBI CONTAINS THE PBI WITH THE DATA
// NOTE THAT WHEN WE START, WE MAY NOT YET KNOW THE SOCKET
// NUMBER OF THE FOREIGN SOCKET.....
[
LET LONGTIMER = NIL; SETTIMER(LV LONGTIMER,TIMEOUT)
[
LET INPBI = NIL
LET INSEQNUM = NIL
// WAIT FOR AN INCOMING PACKET
BLOCK() REPEATUNTIL (SOC!IQHEAD NE 0) |
(TIMEOUT NE -1 & TIMERHASEXPIRED(LV LONGTIMER))
IF TIMEOUT NE -1 & TIMERHASEXPIRED(LV LONGTIMER) THEN
RESULTIS EFTPTIMEOUT
INPBI:= DEQUEUE(LV SOC!IQ)
IF INPBI EQ 0 THEN CALLSWAT("[EFTP] - IQ EMPTY.")
INSEQNUM:= INPBI!ID2
// SEE IF WE ARE ALREADY COMMITTED TO A FILE TRANSFER
IF SOC!TRANSFERNOTSTARTED THEN
[
// NO ESTABLISHED FILE TRANSFER IS IN PROGRESS.
// TO START A FILE TRANSFER, HIS MUST BE A VALID PACKET 0,
// AND ITS SOURCE MUST MATCH OUR SOCKET'S
// DESTINATION, OR WE MUST BE LISTENING.
LET ISFORUS = (((SOC!FRNHOST & #377) EQ 0) | // [ WE ARE LISTENING ] OR
(SOC!FRNPORT EQ INPBI!SPORT)) & // [ HIS SOURCE IS US ]
((INPBI!TYPE & #377) EQ TYPEEFTPDATA) // AND IT'S A VALID PACKET
TEST ISFORUS & INSEQNUM EQ 0
THEN // ESTABLISH A "CONNECTION"
[
SOC!TRANSFERNOTSTARTED:= FALSE
SOC!SEQNUM:= 0
MOVEBLOCK(LV SOC!FRNPORT,
LV INPBI!SPORT,3)
]
OR // RESTART REQUEST OR RANDOM PACKET FROM ANOTHER HOST
[
IF ISFORUS THEN SENDEFTPABORT(SOC, OUTOFSYNCHABORT,
"YOUR SENDER HAS GOTTEN (SIC) OUT OF SYNCH", INPBI)
RELEASEPBI(INPBI)
TEST ISFORUS THEN RESULTIS EFTPNOTFIRSTSYNCH OR LOOP
]
]
//IF YOU REACH HERE, THE TRANSFER HAS ALREADY COMMENCED
UNLESS MULTEQ(LV SOC!FRNSOCKET,LV INPBI!SSOCKET,2) DO
[
IF (INPBI!TYPE & #377) EQ TYPEEFTPDATA & INSEQNUM EQ 0 THEN
[
SENDEFTPABORT(SOC,RECEIVERBUSYABORT,
"RECEIVER BUSY, PLEASE TRY AGAIN LATER.",INPBI)
SOC!SOMEONEELSEWAITING:= TRUE
]
RELEASEPBI(INPBI)
LOOP //WAIT FOR NEXT INPUT
]
//IF WE RECEIVE A DATA PACKET WITH SEQUENCE NUMBER 0
//FROM OUR PARTNER, THEN ASSUME HE WANTS TO RESTART.
IF INSEQNUM EQ 0 & SOC!SEQNUM GR 1 THEN
[ RELEASEPBI(INPBI); RESULTIS EFTPRESETRECEIVED ]
//CHECK THE SEQUENCE NUMBER -- SHOULD BE EXPECTED OR EXPECTED-1
IF (SOC!SEQNUM-INSEQNUM) RSHIFT 1 NE 0 THEN
[
SENDEFTPABORT(SOC,OUTOFSYNCHABORT,
"YOUR SENDER HAS GOTTEN OUT OF SYNCH",INPBI)
RELEASEPBI(INPBI)
RESULTIS EFTPABORTSENT
]
SWITCHON (INPBI!TYPE & #377) INTO
[
CASE TYPEEFTPDATA:
[
LET DATABYTES = NIL
ACKEFTPPACKET(SOC,INPBI)
IF INSEQNUM NE SOC!SEQNUM THEN
[ RELEASEPBI(INPBI); LOOP ] //RETRANSMISSION
SOC!SEQNUM:= SOC!SEQNUM+1
DATABYTES:= INPBI!LENGTH - PUPOVBYTES
RV LVPBI:= INPBI
RESULTIS DATABYTES //AND RETURN
]
CASE TYPEEFTPEND:
[
LET DALLYTIMER = NIL
ACKEFTPPACKET(SOC,INPBI); RELEASEPBI(INPBI)
IF INSEQNUM NE SOC!SEQNUM LOOP //RETRANSMISSION
SOC!SEQNUM:= SOC!SEQNUM+1
SETTIMER(LV DALLYTIMER,DALLYTIMEOUT)
[
BLOCK() REPEATUNTIL SOC!IQHEAD NE 0 |
TIMERHASEXPIRED(LV DALLYTIMER)
IF TIMERHASEXPIRED(LV DALLYTIMER) THEN
RESULTIS EFTPENDRECEIVED
INPBI:= DEQUEUE(LV SOC!IQ)
IF INPBI EQ 0 THEN CALLSWAT("[EFTP] - IQ EMPTY.")
IF (INPBI!TYPE & #377) NE TYPEEFTPEND THEN
[ RELEASEPBI(INPBI); LOOP ]
IF SOC!SEQNUM EQ INPBI!ID2 THEN
[ RELEASEPBI(INPBI); RESULTIS EFTPENDRECEIVED ]
// WAS A RETRANSMISSION OF FIRST END, ACK IT
ACKEFTPPACKET(SOC,INPBI); RELEASEPBI(INPBI)
] REPEAT
ENDCASE
]
CASE TYPEEFTPABORT:
[
IF SOC!ABORTPBI NE 0 THEN
RELEASEPBI(SOC!ABORTPBI)
SOC!ABORTPBI:= INPBI
RESULTIS EFTPABORTRECEIVED
]
]
RELEASEPBI(INPBI)
] REPEAT
]
//----------------------------------------------------------------
AND ACKEFTPPACKET(SOC,PBI) BE
//----------------------------------------------------------------
[
// CONSTRUCT THE OUTGOING ACK PACKET
LET ACKPBI = GETPBI(SOC,FALSE)
ACKPBI!ID2:= PBI!ID2
COMPLETEPUP(ACKPBI,TYPEEFTPACK,0+PUPOVBYTES)
]
//----------------------------------------------------------------
AND GETEFTPABORT(SOC) = SOC!ABORTPBI
//----------------------------------------------------------------
//----------------------------------------------------------------
AND SENDEFTPABORT(SOC,ABORTCODE,ABORTSTRING,PBI) BE
//----------------------------------------------------------------
// CONSTRUCT THE OUTGOING ABORT PACKET,
// WILL GET SENT TO YOUR CURRENT FOREIGN PORT
[
LET ABORTPBI = GETPBI(SOC,FALSE)
IF PBI NE 0 THEN
[
ABORTPBI!ID2:= PBI!ID2
SETPUPDPORT(ABORTPBI,LV PBI!SPORT)
]
ABORTPBI!ID2:= SOC!SEQNUM
ABORTPBI!(WORDS+0):= ABORTCODE
APPENDSTRINGTOPUP(ABORTPBI,3,ABORTSTRING)
COMPLETEPUP(ABORTPBI,TYPEEFTPABORT,0)
]